# @File    : control_point_caculatorX.py

import sys
from typing import Union

import numpy
import pandas
from PyQt5 import QtGui, QtCore
from PyQt5.QtCore import QObject
from PyQt5.QtWidgets import QLineEdit

import autogen.control_point_calculator
import common
import ezmath
import ezqt
import painter
from ezqt import QDoubleValidatorAllowNan


class ControlPointCalculatorX(autogen.control_point_calculator.Ui_ctrl_pts_caculator, QObject):
    sig_arc_calculator_rotation_axis_freedom_changed = QtCore.pyqtSignal(int)  # 控制点计算器中的圆弧旋转轴的自由度为1

    def __init__(self, parent: ezqt.MainWindowKnowItselfShown, hm: common.libhallmachine.HallMachine,
                 main_timer=common.DEFAULT_MAIN_TIMER):
        print("初始化+1")
        super(ControlPointCalculatorX, self).__init__()
        self.parent: ezqt.MainWindowKnowItselfShown = parent
        self.setupUi(parent)
        self.hm = hm
        self.main_timer = main_timer
        self.canvas = ezqt.EzCanvasWidget(self.widget_for_fig)
        self.calculation_result: common.Trajectory = None
        self.__rotation_axis_line_edits: list[Union[QLineEdit, QLineEdit]] = [self.lineEdit_rotationaxis_x,
                                                                              self.lineEdit_rotationaxis_y,
                                                                              self.lineEdit_rotationaxis_z]
        self.__series_line_edits_null_status = pandas.Series(
            {lineEdit.objectName(): (lineEdit.text() == "") for lineEdit in
             self.__rotation_axis_line_edits
             }, )  # 用于保存轴相关的3个lineedit的状态。若为空，则为True
        self.__disabled_line_edit_names = set()
        self.__set_validator()
        self.__init_canvas()
        self.connect_all()
        self.__update_arc_freedom()

    def __update_arc_freedom(self):
        freedom = self.__series_line_edits_null_status.sum()
        self.sig_arc_calculator_rotation_axis_freedom_changed.emit(freedom)
        return freedom

    def __template_on_axis_line_edit_editing_finished(self, line_edit: QLineEdit, ):
        print("%s 结束编辑的text = %s" % (line_edit.objectName(), line_edit.text()))
        delta_freedom = (line_edit.text() == "")
        self.__series_line_edits_null_status[line_edit.objectName()] = delta_freedom
        self.__update_arc_freedom()

    def __on_arc_calculator_rotation_axis_freedom_changed(self, freedom):
        print("Freedom changed, now %s" % freedom)
        if freedom == 1:
            free_line_edit_name = \
                self.__series_line_edits_null_status[self.__series_line_edits_null_status == True].index[0]
            free_line_edit = self.frame.findChild(QLineEdit, free_line_edit_name)
            free_line_edit.setDisabled(True)
            self.__disabled_line_edit_names.add(free_line_edit_name)
        else:
            for i in range(len(self.__disabled_line_edit_names)):
                disabled_name = self.__disabled_line_edit_names.pop()
                disabled_edit = self.frame.findChild(QLineEdit, disabled_name)
                disabled_edit.setEnabled(True)

    def __init_canvas(self):
        """
        初始化绘图区
        """
        self.__plot_example_arc()

    def __plot_example_arc(self):
        axis = numpy.array([0, -100, 0])
        ax, control_pts, center_pt = painter.plot_arc(self.canvas.canvas_qtagg.figure, numpy.array([0, 0, 0]),
                                                      numpy.array([0, 0, 200]),
                                                      300, 25, axis)
        ax.set_title("Example")
        self.canvas.canvas_qtagg.draw()
        self.calculation_result = common.Trajectory()
        self.calculation_result.df[common.Trajectory.columns_xyz] = control_pts

    def connect_all(self):
        self.pushButton_gen_arc.clicked.connect(self.__on_push_gen_arc)
        self.pushButton_cur_pt1.clicked.connect(self.__on_current_pt_as_pt1)
        self.pushButton_cur_pt2.clicked.connect(self.__on_current_pt_as_pt2)
        self.pushButton_emit_calculated_ctrl_pts.clicked.connect(self.__emit_calculated_ctrl_pts)
        self.lineEdit_rotationaxis_x.editingFinished.connect(
            lambda: self.__template_on_axis_line_edit_editing_finished(line_edit=self.lineEdit_rotationaxis_x))
        self.lineEdit_rotationaxis_y.editingFinished.connect(
            lambda: self.__template_on_axis_line_edit_editing_finished(line_edit=self.lineEdit_rotationaxis_y))
        self.lineEdit_rotationaxis_z.editingFinished.connect(
            lambda: self.__template_on_axis_line_edit_editing_finished(line_edit=self.lineEdit_rotationaxis_z))
        self.sig_arc_calculator_rotation_axis_freedom_changed.connect(
            self.__on_arc_calculator_rotation_axis_freedom_changed)

    def __emit_calculated_ctrl_pts(self):
        if self.calculation_result:
            self.main_timer.sig_insert_control_pts.emit(self.calculation_result)

    def __get_current_pt(self) -> common.Vec3:
        return common.UMAC_Pos.from_UMACData(self.hm.umac_data_).to_Vec3d()

    def __on_current_pt_as_pt1(self):
        cur_pt = self.__get_current_pt()
        self.lineEdit_pt1_x_mm.setText(cur_pt.x)
        self.lineEdit_pt1_y_mm.setText(cur_pt.y)
        self.lineEdit_pt1_z_mm.setText(cur_pt.z)

    def __on_current_pt_as_pt2(self):
        cur_pt = self.__get_current_pt()
        self.lineEdit_pt2_x_mm.setText(cur_pt.x)
        self.lineEdit_pt2_y_mm.setText(cur_pt.y)
        self.lineEdit_pt2_z_mm.setText(cur_pt.z)

    def __on_push_gen_arc(self):
        try:
            P1 = numpy.array(
                [self.lineEdit_pt1_x_mm.text(), self.lineEdit_pt1_y_mm.text(), self.lineEdit_pt1_z_mm.text(), ]).astype(
                float)
            P2 = numpy.array(
                [self.lineEdit_pt2_x_mm.text(), self.lineEdit_pt2_y_mm.text(), self.lineEdit_pt2_z_mm.text(), ]).astype(
                float)
            rho = float(self.lineEdit_rho_mm.text())
            ds = float(self.lineEdit_arc_ds_mm.text())
            axis_direction = numpy.array(
                [self.lineEdit_rotationaxis_x.text(), self.lineEdit_rotationaxis_y.text(),
                 self.lineEdit_rotationaxis_z.text(), ])
            axis_direction = ezmath.as_float_null_to_nan(axis_direction)
            ezmath.fill_nan_for_perpendicular(P2 - P1, axis_direction)
            print(axis_direction)
            _, control_pts, __ = painter.plot_arc(self.canvas.canvas_qtagg.figure, P1, P2, rho, ds, axis_direction)
            self.calculation_result = common.Trajectory()
            self.calculation_result.df[common.Trajectory.columns_xyz] = control_pts
            self.canvas.canvas_qtagg.draw()
        except Exception as e:
            print(e)
            self.__plot_example_arc()
            raise e

    def __set_validator(self):
        self.lineEdit_pt1_x_mm.setValidator(QtGui.QDoubleValidator())
        self.lineEdit_pt1_y_mm.setValidator(QtGui.QDoubleValidator())
        self.lineEdit_pt1_z_mm.setValidator(QtGui.QDoubleValidator())
        self.lineEdit_pt2_x_mm.setValidator(QtGui.QDoubleValidator())
        self.lineEdit_pt2_y_mm.setValidator(QtGui.QDoubleValidator())
        self.lineEdit_pt2_z_mm.setValidator(QtGui.QDoubleValidator())
        self.lineEdit_rho_mm.setValidator(QtGui.QDoubleValidator())
        self.lineEdit_arc_ds_mm.setValidator(QtGui.QDoubleValidator())
        self.lineEdit_rotationaxis_x.setValidator(QDoubleValidatorAllowNan())
        self.lineEdit_rotationaxis_y.setValidator(QDoubleValidatorAllowNan())
        self.lineEdit_rotationaxis_z.setValidator(QDoubleValidatorAllowNan())


if __name__ == "__main__":
    from PyQt5.Qt import QApplication

    app = QApplication([])
    mainwindow = ezqt.MainWindowKnowItselfShown()
    hm = common.HallMachine()
    calculator_ui = ControlPointCalculatorX(mainwindow, hm)
    mainwindow.show()
    common.DEFAULT_MAIN_TIMER.sig_setup_canvas_on_calculator.emit()
    sys.exit(app.exec_())
